#include "task.h"
#include "uart.h"
#include "led_loop.h"
#include "wdt.h"
#include "wire.h"
#include "i2c.h"
#include "ds1302.h"
#include "ds18b20.h"
#include "lcd1602.h"
#include "buzzer.h"
#include "segment.h"
#include "m_key.h"
#include "m_led.h"
#include "i_key.h"
#include "pcf8591.h"
#include "at24c02.h"
#include "ir1838.h"
#include "step_motor.h"

/* define your task func start */
#define TASK_NUM 3
static void s_task_0(void);
static void s_task_1(void);
static void s_task_2(void);
/* define your task func end */

/* define your task handle start */
static volatile task_t s_task_panel[TASK_NUM];
/* define your task handle end */

/* define your data panel start */
static volatile led_t s_led_panel; /* rigister led panel */
/* define your data panel end */

/**
 * @brief s_task_0
 *
 */
static void s_task_0(void)
{
#if TASK_DEBUG
    printf("task 0\r\n");
#endif

#if I_KEY_TASK
    i_key_scan_demo();
#endif
#if M_KEY_TASK
    matrix_key_scan_demo();
#endif
#if PCF8591_DAC_TASK
    pcf8591_dac_demo();
#endif
#if IR1838_TASK
    ir1838_demo();
#endif
#if STEP_MOTOR_TASK
    /* scan key and set step angle start */
    key_scan(key_msg_struct_panel(), key_struct_panel());
    if (key_msg_struct_panel()->pressed)
    {
        key_msg_struct_panel()->pressed = 0; /* clear key_msg status */
        switch (key_msg_struct_panel()->id)
        {
        case 0:
            step_motor_struct_panel()->step_direct = !step_motor_struct_panel()->step_direct;
            lcd1602_display_one_num(15, 0, step_motor_struct_panel()->step_direct);
            break;
        case 1:
            step_motor_struct_panel()->step_angle = 2048; /* 180° */
            lcd1602_display_str(0, 1, "angle:180'");
            lcd1602_display_one_num(15, 0, step_motor_struct_panel()->step_direct);
            break;
        case 2:
            step_motor_struct_panel()->step_angle = 1024; /* 90° */
            lcd1602_display_str(0, 1, "angle:90' ");
            lcd1602_display_one_num(15, 0, step_motor_struct_panel()->step_direct);
            break;
        case 3:
            step_motor_struct_panel()->step_angle = 512; /* 45° */
            lcd1602_display_str(0, 1, "angle:45' ");
            lcd1602_display_one_num(15, 0, step_motor_struct_panel()->step_direct);
            break;
        default:
            break;
        }
    }
    /* scan key and set step angle start */
#endif
}

/**
 * @brief s_task_1
 *
 */
static void s_task_1(void)
{
    char lcd_dis_str[10];
#if TASK_DEBUG
    printf("task 1\r\n");
#endif

    clear_wdt(); /* feed dog proc */
#if LED_LOOP_TASK
    led_loop_proc(&s_led_panel); /* led loop proc */
#endif
#if DS1302_TASK
    ds1302_proc();
    lcd1602_display_str(0, 0, "Date:");
    lcd1602_display_str(5, 0, "20");
    lcd1602_display_one_num(7, 0, ds1302_get_time(YEAR) / 10);
    lcd1602_display_one_num(8, 0, ds1302_get_time(YEAR) % 10);
    lcd1602_display_char(9, 0, '-');
    lcd1602_display_one_num(10, 0, ds1302_get_time(MONTH) / 10);
    lcd1602_display_one_num(11, 0, ds1302_get_time(MONTH) % 10);
    lcd1602_display_char(12, 0, '-');
    lcd1602_display_one_num(13, 0, ds1302_get_time(MDAY) / 10);
    lcd1602_display_one_num(14, 0, ds1302_get_time(MDAY) % 10);
    lcd1602_display_str(0, 1, "Time:");
    lcd1602_display_one_num(5, 1, ds1302_get_time(HOUR) / 10);
    lcd1602_display_one_num(6, 1, ds1302_get_time(HOUR) % 10);
    lcd1602_display_char(7, 1, ':');
    lcd1602_display_one_num(8, 1, ds1302_get_time(MIN) / 10);
    lcd1602_display_one_num(9, 1, ds1302_get_time(MIN) % 10);
    lcd1602_display_char(10, 1, ':');
    lcd1602_display_one_num(11, 1, ds1302_get_time(SEC) / 10);
    lcd1602_display_one_num(12, 1, ds1302_get_time(SEC) % 10);
#endif
#if DS1802_TASK
    ds18b20_proc();
    sprintf(lcd_dis_str, "%.2fC", ds18b20_struct_panel()->temp_value);
    lcd1602_display_str(0, 0, "TEMP:");
    lcd1602_display_str(5, 0, lcd_dis_str);
#endif
#if LCD1602_TASK
    lcd1602_display_str(3, 0, "Hello World!");
    lcd1602_display_str(1, 1, "What can I Say!");
#endif
#if PCF8591_ADC_TASK
    pcf8591_adc_demo();
    sprintf(lcd_dis_str, "%.2f", 5.0 * ((float)pcf8591_adc_struct_panel()->adc_channel_0 / 255.0));
    lcd1602_display_str(0, 0, "C1:");
    lcd1602_display_str(3, 0, lcd_dis_str);
    sprintf(lcd_dis_str, "%.2f", 5.0 * ((float)pcf8591_adc_struct_panel()->adc_channel_1 / 255.0));
    lcd1602_display_str(9, 0, "C2:");
    lcd1602_display_str(12, 0, lcd_dis_str);
    sprintf(lcd_dis_str, "%.2f", 5.0 * ((float)pcf8591_adc_struct_panel()->adc_channel_2 / 255.0));
    lcd1602_display_str(0, 1, "C3:");
    lcd1602_display_str(3, 1, lcd_dis_str);
    sprintf(lcd_dis_str, "%.2f", 5.0 * ((float)pcf8591_adc_struct_panel()->adc_channel_3 / 255.0));
    lcd1602_display_str(9, 1, "C4:");
    lcd1602_display_str(12, 1, lcd_dis_str);
#endif
#if BUZZER_TASK
    buzzer_demo();
#endif
}

/**
 * @brief s_task_2
 *
 */
static void s_task_2(void)
{
#if TASK_DEBUG
    printf("task 2\r\n");
#endif

#if SEGMENT_TASK
    segment_test_proc();
#endif
#if AT24C02_TASK
    at24_wr_rd_demo();
#endif
}

/**
 * @brief task_create_check
 *
 */
static void task_create_check(void)
{
    uint8_t i;
    for (i = 0; i < TASK_NUM; i++)
    {
        if (s_task_panel[i].operation != NULL)
        {
#if TASK_DEBUG
            printf("task_%bd create ok.[period = %d , tick = %d]\r\n", i, s_task_panel[i].period, s_task_panel[i].tick);
#endif
        }
        else
        {
#if TASK_DEBUG
            printf("task_%bd create fail.[task func is null]\r\n", i);
#endif
        }
    }
}

/**
 * @brief task_num
 *
 * @return uint8_t
 */
uint8_t task_num(void)
{
    return TASK_NUM;
}

/**
 * @brief task_creat
 *
 */
void task_creat(void)
{
    /* component init start */
#if LED_LOOP_TASK
    hj_c52_reset();
    led_init(&s_led_panel); // init led loop
#endif
#if DS1802_TASK
    hj_c52_reset();
    lcd1602_init();
#endif
#if DS1302_TASK
    hj_c52_reset();
    lcd1602_init();
    //ds1302_set_time(24, 6, 15, 1, 0, 0, 6);
#endif
#if LCD1602_TASK
    hj_c52_reset();
    lcd1602_init();
#endif
#if BUZZER_TASK
    hj_c52_reset();
    buzzer_init();
#endif
#if I_KEY_TASK
    hj_c52_reset();
    lcd1602_init();
#endif
#if M_KEY_TASK
    hj_c52_reset();
    lcd1602_init();
#endif
#if PCF8591_ADC_TASK
    hj_c52_reset();
    lcd1602_init();
    pcf8591_init(); /* wait 0x80 data */
#endif
#if AT24C02_TASK
    hj_c52_reset();
    lcd1602_init();
    at24_wr_rd_demo_init();
#endif
#if IR1838_TASK
    hj_c52_reset();
    lcd1602_init();
    ir1838_init();
#endif
#if M_LED_TASK
    hj_c52_reset();
#endif
#if STEP_MOTOR_TASK
    hj_c52_reset();
    lcd1602_init();
    lcd1602_display_str(0,0,"Step Motor");
    lcd1602_display_one_num(15, 0, step_motor_struct_panel()->step_direct);
#endif
    /* component init end */

    /* create task 0 start */
    s_task_panel[0].operation = s_task_0;
    s_task_panel[0].period = 2;
    s_task_panel[0].tick = s_task_panel[0].period;
    /* create task 0 end */

    /* create task 1 start */
    s_task_panel[1].operation = s_task_1;
    s_task_panel[1].period = 80;
    s_task_panel[1].tick = s_task_panel[1].period;
    /* create task 1 end */

    /* create task 2 start */
    s_task_panel[2].operation = s_task_2;
    s_task_panel[2].period = 200;
    s_task_panel[2].tick = s_task_panel[2].period;
    /* create task 2 end */

    /* task create check start */
    task_create_check();
    /* task create check end */
}

/**
 * @brief task_handle
 *
 * @return task_t
 */
task_t *task_handle(void)
{
    return s_task_panel;
}

/**
 * @brief task_schedule
 *
 */
void task_schedule(void)
{
    uint8_t i;
    for (i = 0; i < TASK_NUM; i++)
    {
        /* check task tick and task criticality start */
        if ((s_task_panel[i].tick == 0 || s_task_panel[i].tick > s_task_panel[i].period) && s_task_panel[i].operation != NULL)
        {
            s_task_panel[i].tick = s_task_panel[i].period; /* reset task tick */
            s_task_panel[i].operation();                   /* run task operation */
        }
        /* check task tick and task criticality end */
    }
}
